
#include <SdFat.h>
#include <SdFatUtil.h>
#include "TimerOne.h"
#include <avr/io.h> 
#include <avr/interrupt.h> 

//#define BLOCK_COUNT 100L
#define BLOCK_COUNT 100000L
#define SENSOR_COUNT 6
#define error(s) error_P(PSTR(s))

uint8_t data1[512];
uint8_t data2[512];
volatile int idx=0;
volatile int bufferidx=1;
volatile int  w=0;
volatile int overflowcounter=0;
volatile byte readcount=0;
uint32_t currentBlock=0;
volatile uint8_t currentSensor=0;

Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
uint32_t bgnBlock, endBlock,b;






void setup()
{
  Serial.begin(115200);
  Serial.flush();
  PgmPrintln("Type any character to start");
  while (!Serial.available());

  w=0;
  bufferidx=1;
  initFS();
  initADC();
  initTimer();
  Serial.println(millis());
}


void loop()
{
  //if nothing to do return back to main!
  if(w==0){
    return;
  }
  //if we need to write buffer1
  if(w==1)
  {
    if (!card.writeData(data1)) //write buffer1
    { 
      error("writeData failed");
    }
  }
  else
  {
    if (!card.writeData(data2)) {
      error("writeData failed");
    }
  }
  
  w=0;//set w=0, we are done writing
  currentBlock++;//increment the block counter

  //if we are over the current block count then disable and spin
  if(currentBlock>=BLOCK_COUNT){
    Serial.println(millis());
    Timer1.stop();
    Serial.print(overflowcounter,DEC);
    PgmPrintln("Done");
    while(1==1);    
  }
}

void initTimer()
{
  Timer1.initialize(625);         // initialize timer1, set for 1600 Hz
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
}

//when the time triggers, start sampling
void callback()
{
  initADC(); 
}

//FS iniitialization routine
void initFS()
{
  if (!card.init(SPI_FULL_SPEED)) {
    error("card.init failed");
  }
  if (!volume.init(&card)) 
  {
    error("volume.init failed");
  }

  if (!root.openRoot(&volume)) error("openRoot failed");

  SdFile::remove(&root, "RAW.TXT");

  if (!file.createContiguous(&root, "RAW.TXT", 512UL*BLOCK_COUNT)) {
    error("createContiguous failed");
  }
  // get the location of the file's blocks
  if (!file.contiguousRange(&bgnBlock, &endBlock)) {
    error("contiguousRange failed");
  }
  volume.cacheClear();
  //data1 = volume.cacheClear();

  if (!card.erase(bgnBlock, endBlock)) 
  {
    error("card.erase failed");
  }
  if (!card.writeStart(bgnBlock, BLOCK_COUNT)) {
    error("writeStart failed");
  }
}

//Set parameters for ADC system (NEED TO VERIFY FLAGS!!)
void initADC()
{
  currentSensor=0;
  ADCSRA = _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0);
  ADMUX = (1<<REFS0)|(1<<ADLAR); //use AVCC as reference, set to left adjusted, select ADC0 
  ADCSRA = (1<<ADEN)|(1<<ADIE)|(1<<ADATE); //enable ADC, ADC interrupt and ADC auto trigger 
  ADCSRA = (1<<ADEN)|(1<<ADIE); //enable ADC, ADC interrupt and ADC auto trigger 
  //Because ADCSRB is not set and the ADATE is set, the ADC is in free running mode 
  ADCSRA |= _BV(ADSC);

}



//ISR for the analog conversion, it throws the first value away as its usually garbage.
ISR(ADC_vect) 
{ 
  if(readcount>0) //if its the second reading
  {
    readcount=0;
    if(bufferidx==1)
    {
      data1[idx]=(byte)ADCL;  //must read from ADCL first
      index();
      data1[idx]=(byte)ADCH; 
      index();
    }
    else
    {
      data2[idx]=(byte)ADCL;  
      index();
      data2[idx]=(byte)ADCH; 
      index();
    }
    currentSensor++; 
    if(currentSensor>=SENSOR_COUNT)//if we are done scanning
    {
      return; 
    }
  }
  
  readcount++;
  ADMUX = (1<<REFS0)|(1<<ADLAR)|currentSensor; //setup the next conversion
  ADCSRA |= (1<<ADSC);  //start the conversion

  //  
} 




//the index function provides wraparound capablities as well as swapping the buffers..
void index()
{
  idx++; 
  if(idx>=512) 
  { 
    idx=0; //set idx back to 0
    if(bufferidx==2){  
      bufferidx=1;     //swap to the other buffer
      if(bufferidx==w) //if we are toggling to the buffer thats in progress.. we must have overflowed
      { 
        overflowcounter++; 
      } 
      w=2; //tell the main loop that buffer 2 is ready
    } 
    else 
    { 
      bufferidx=2; 
      if(bufferidx==w) 
      { 
        overflowcounter++; 
      } 
      w=1; 
    } 
  } 
}



void error_P(const char* str) {
  PgmPrint("error: ");
  SerialPrintln_P(str);
  if (card.errorCode()) {
    PgmPrint("SD error: ");
    Serial.print(card.errorCode(), HEX);
    Serial.print(',');
    Serial.println(card.errorData(), HEX);
  }
  while(1);
}

































